home *** CD-ROM | disk | FTP | other *** search
/ Experimental BBS Explossion 3 / Experimental BBS Explossion III.iso / gus / mikmod2.zip / MODLOAD.C < prev    next >
C/C++ Source or Header  |  1993-12-02  |  8KB  |  448 lines

  1. /*
  2.     MODLOAD.C
  3.  
  4.     Or how to load a module in C. Progged by MikMak :)
  5. */
  6.  
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include <ctype.h>
  11. #include <alloc.h>
  12. #include <mytypes.h>
  13. #include "modload.h"
  14.  
  15.  
  16. FILE *fp;           // yuck... it's global
  17.  
  18.  
  19. MODULEHEADER mh;
  20.  
  21. int (*SampleLoader)(int samplenr,FILE *fp,ULONG size)=NULL;    // The callback sample load routine
  22. int    ml_numchn;              // number of channels in use
  23. int ml_numpat;              // number of patterns used
  24. int ml_numsmp;              // number of samples used
  25. int ml_patsiz;              // size (bytecount) per pattern
  26. char ml_songname[21];       // CSTR songname
  27. UBYTE ml_songlength;        // songlength
  28. UBYTE ml_positions[128];    // song sequence
  29. char *ml_modtype;           // module type name
  30. void far *ml_patlist[128];  // a list of all patterns
  31. SAMPLEINFO ml_samples[31];  // all samples
  32.  
  33. int ml_errno=0;
  34.  
  35.  
  36. char *ml_errlist[]={
  37.     "Okay",
  38.     "Error opening modfile",
  39.     "Error loading module header",
  40.     "Unknown type of module",
  41.     "Failed allocating pattern",
  42.     "EOF while loading pattern",
  43.     "Failed allocating sample",
  44.     "EOF while loading sample",
  45.     "No sample loader defined. (use ML_RegisterSampleLoader())",
  46.     "Sample load failed"
  47. };
  48.  
  49.  
  50. enum {
  51.     ERROR_OKAY=0,
  52.     ERROR_OPENING_FILE,
  53.     ERROR_LOADING_HEADER,
  54.     ERROR_NOT_A_MODULE,
  55.     ERROR_ALLOC_PATTERN,
  56.     ERROR_EOF_PATTERNS,
  57.     ERROR_ALLOC_SAMPLE,
  58.     ERROR_EOF_SAMPLE,
  59.     ERROR_NO_LOADER,
  60.     ERROR_SAMPLE_FAILED
  61. };
  62.  
  63.  
  64. char *modtypes[]={
  65.     "M.K.",             // protracker
  66.     "FLT4",             // startracker 4 channel
  67.     "FLT8",             // startracker 8 channel
  68.     "4CHN",             // fasttracker 4 channel
  69.     "6CHN",             // fasttracker 6 channel
  70.     "8CHN"              // fasttracker 8 channel
  71. };
  72.  
  73.  
  74. char *modtypenames[]={
  75.     "Protracker",
  76.     "Startracker",
  77.     "Startracker",
  78.     "Fasttracker",
  79.     "Fasttracker",
  80.     "Fasttracker",
  81.     "Unknown",
  82.     "Unknown",
  83.     "Unknown",
  84. };
  85.  
  86.  
  87. char modtypechannels[]={
  88.     4,4,8,4,6,8,4,6,8
  89. };
  90.  
  91.  
  92.  
  93.  
  94.  
  95.  
  96.  
  97. #pragma warn -rvl
  98.  
  99. ULONG rlong(ULONG p)
  100. /*
  101.     Motorola long -> intel long
  102. */
  103. {
  104.     asm{
  105.         push ds
  106.         lds  ax,p
  107.         mov  dx,ds
  108.         xchg dl,dh
  109.         xchg al,ah
  110.         xchg dx,ax
  111.         pop  ds
  112.     }
  113. }
  114.  
  115.  
  116.  
  117. UWORD rword(UWORD p)
  118. /*
  119.     Motorola word -> intel word
  120. */
  121. {
  122.     asm{
  123.         mov  ax,p
  124.         xchg al,ah
  125.     }
  126. }
  127.  
  128.  
  129.  
  130. UWORD cword(UWORD *p)
  131. {
  132.     *p=rword(*p);
  133. }
  134.  
  135. #pragma warn +rvl
  136.  
  137.  
  138.  
  139.  
  140. void ConvertStr(char *d,char *s,int len)
  141. {
  142.     strncpy(d,s,len);
  143.     d[len]='\0';
  144. }
  145.  
  146.  
  147.  
  148.  
  149. /*
  150.  
  151. Old (amiga) noteinfo:
  152.  
  153.  _____byte 1_____   byte2_    _____byte 3_____   byte4_
  154. /                \ /      \  /                \ /      \
  155. 0000          0000-00000000  0000          0000-00000000
  156.  
  157. Upper four    12 bits for    Lower four    Effect command.
  158. bits of sam-  note period.   bits of sam-
  159. ple number.                  ple number.
  160.  
  161.  
  162.  
  163. New (peecee) noteinfo:
  164.  
  165.  _byte 1_   _byte 2_   __byte 3_   _byte 4_
  166. /        \ /        \ /         \ /        \
  167.  00000000   00000000   0000 0000   00000000
  168.   Sample    note nr.   zero  fx     fx data
  169.  
  170. Sample ranges from 0 to 31
  171.  
  172. Note number 0 means no note. ranges from 1 to 36
  173.  
  174. */
  175.  
  176.  
  177.  
  178.  
  179. // Periodtable for Tuning 0, Normal
  180.  
  181. UWORD pertab[36]={
  182.     856,808,762,720,678,640,604,570,538,508,480,453,
  183.     428,404,381,360,339,320,302,285,269,254,240,226,
  184.     214,202,190,180,170,160,151,143,135,127,120,113
  185. };
  186.  
  187.  
  188.  
  189.  
  190. void ML_ConvertPattern(UBYTE far *pattern)
  191. /*
  192.     Translates an amiga type pattern to a pattern with note-numbers
  193.     instead of note-periods
  194. */
  195. {
  196.     int t;
  197.     UBYTE a,b,c;
  198.     UWORD period;
  199.     UBYTE note;
  200.  
  201.     for(t=0;t<(ml_numchn<<6);t++){
  202.  
  203.         a=pattern[0];
  204.         b=pattern[1];
  205.         c=pattern[2];
  206.  
  207.         period=(((UWORD)a&0xf)<<8)+b;
  208.  
  209.         if(period!=0){
  210.             for(note=0;note<36;note++){
  211.                 if(period==pertab[note]) break;
  212.             }
  213.             if(note==36) note=0;    // couldn't find period, kill note
  214.             note++;
  215.         }
  216.         else note=0;
  217.  
  218.         pattern[0]=(a&0xf0)+(c>>4);
  219.         pattern[1]=note;
  220.         pattern[2]&=0x0f;
  221.  
  222.         pattern+=4;
  223.     }
  224. }
  225.  
  226.  
  227.  
  228.  
  229. int ML_GetModuleType(void)
  230. /*
  231.     Determines which type of module is being loaded, and
  232.     sets the variables ml_numchn and ml_modtype accordingly.
  233.  
  234.     returns 0 on error
  235. */
  236. {
  237.     int t;
  238.  
  239.     // find out which ID string
  240.  
  241.     for(t=0;t<6;t++){
  242.         if(!memcmp(mh.magic2,modtypes[t],4)) break;
  243.     }
  244.  
  245.     /* if ID string is unknown, look if magic1 and
  246.        songlength contain reasonable values and try
  247.        to find how many channels the module contains */
  248.  
  249.     if(t==6){
  250.         if(mh.magic1==127 && mh.songlength<=128){
  251.             switch(mh.magic2[3]){
  252.                 case '4': t=6; break;
  253.                 case '6': t=7; break;
  254.                 case '8': t=8; break;
  255.                 default: t=-1; break;
  256.             }
  257.         }
  258.         else t=-1;
  259.     }
  260.  
  261.     /* song is no good.. return error */
  262.  
  263.     if(t==-1){
  264.         ml_errno=ERROR_NOT_A_MODULE;
  265.         return 0;
  266.     }
  267.  
  268.     /* set global variables */
  269.  
  270.     ml_numchn=modtypechannels[t];           // get number of channels
  271.     ml_modtype=modtypenames[t];             // get ascii type of mod
  272.     ml_patsiz=ml_numchn<<8;                 // compute size per pattern
  273.     ConvertStr(ml_songname,mh.songname,20); // make a cstr of songname
  274.     ml_songlength=mh.songlength;            // copy the songlength
  275.     memcpy(ml_positions,mh.positions,128);  // copy the position array
  276.     return 1;
  277. }
  278.  
  279.  
  280.  
  281. int ML_LoadModuleHeader(void)
  282. /*
  283.     Loads the module header and translates Motorola to Intel words.
  284.  
  285.     sets errno and returns 0 on error.
  286. */
  287. {
  288.     int t;
  289.  
  290.     /* read header */
  291.  
  292.     if((fread(&mh,sizeof(MODULEHEADER),1,fp)!=1)){
  293.         ml_errno=ERROR_LOADING_HEADER;
  294.         return 0;
  295.     }
  296.  
  297.     /* sample info to intel format */
  298.  
  299.     for(t=0;t<31;t++){
  300.         cword(&mh.samples[t].length);
  301.         cword(&mh.samples[t].reppos);
  302.         cword(&mh.samples[t].replen);
  303.     }
  304.     return 1;
  305. }
  306.  
  307.  
  308.  
  309. int ML_LoadPatterns(void)
  310. /*
  311.     Loads all patterns into the patternlist
  312.  
  313.     sets errno and returns 0 on error.
  314. */
  315. {
  316.     int t;
  317.  
  318.     /* First, count the number of patterns */
  319.  
  320.     ml_numpat=0;
  321.  
  322.     for(t=0;t<128;t++){        // <-- BUGFIX... have to check ALL positions
  323.         if(mh.positions[t] > ml_numpat){
  324.             ml_numpat=mh.positions[t];
  325.         }
  326.     }
  327.     ml_numpat++;
  328.  
  329.     for(t=0;t<ml_numpat;t++){
  330.  
  331.         /* For each pattern, allocate a chunk
  332.            of memory and load the pattern */
  333.  
  334.         if((ml_patlist[t]=farmalloc(ml_patsiz))==NULL){
  335.             ml_errno=ERROR_ALLOC_PATTERN;
  336.             return 0;
  337.         }
  338.         if(fread(ml_patlist[t],ml_patsiz,1,fp)!=1){
  339.             ml_errno=ERROR_EOF_PATTERNS;
  340.             return 0;
  341.         }
  342.         ML_ConvertPattern(ml_patlist[t]);   // convert pattern
  343.     }
  344.     return 1;
  345. }
  346.  
  347.  
  348.  
  349.  
  350. int ML_LoadSamples(void)
  351. /*
  352.     Loads all samples into the sampleinfo table.
  353.  
  354.     sets errno and returns 0 on error
  355. */
  356. {
  357.     int t;
  358.  
  359.     SAMPLEINFO *d;  // new sampleinfo structure
  360.     MSAMPINFO *s;   // old module sampleinfo
  361.  
  362.     ml_numsmp=0;    // reset number of samples
  363.     s=mh.samples;   // init source pointer
  364.     d=ml_samples;   // init dest pointer
  365.  
  366.     if(SampleLoader==NULL){
  367.         ml_errno=ERROR_NO_LOADER;
  368.         return 0;
  369.     }
  370.  
  371.     for(t=0;t<31;t++){
  372.  
  373.         // convert the samplename
  374.  
  375.         ConvertStr(d->samplename,s->samplename,22);
  376.  
  377.         /* init the sampleinfo variables and
  378.            convert the size pointers to longword format */
  379.  
  380.         d->finetune=s->finetune;
  381.         d->volume=s->volume;
  382.         d->reppos=s->reppos<<1;
  383.         d->replen=s->replen<<1;
  384.         d->length=s->length<<1;
  385.  
  386.         /* sample has to be loaded ? -> increase
  387.            number of samples and allocate memory and
  388.            load sample */
  389.  
  390.         if(d->length!=0){
  391.             ml_numsmp++;
  392.  
  393.             if(!SampleLoader(t,fp,d->length)){
  394.                 ml_errno=ERROR_SAMPLE_FAILED;
  395.                 return 0;
  396.             }
  397.         }
  398.         s++;    // point to next source sampleinfo
  399.         d++;    // point to next destiny sampleinfo
  400.     }
  401.     return 1;
  402. }
  403.  
  404.  
  405.  
  406. void ML_RegisterSampleLoader(int (*Loader)(int samplenr,FILE *fp,ULONG size))
  407. {
  408.     SampleLoader=Loader;
  409. }
  410.  
  411.  
  412. int ML_LoadModule(char *filename,FILE *ufp)
  413. /*
  414.     Loads a module. (By filename or file-pointer).
  415.  
  416.     returns 0 on error.
  417. */
  418. {
  419.     int modtype;
  420.  
  421.     // reset error variable
  422.  
  423.     ml_errno=ERROR_OKAY;
  424.  
  425.     // open module filename
  426.  
  427.     if(filename!=NULL){
  428.         if((fp=fopen(filename,"rb"))==NULL){
  429.             ml_errno=ERROR_OPENING_FILE;
  430.             return 0;
  431.         }
  432.     }
  433.     else{
  434.         fp=ufp;
  435.     }
  436.  
  437.     // read the module header
  438.  
  439.     if(!ML_LoadModuleHeader()) return 0;    // load module header
  440.     if(!ML_GetModuleType()) return 0;       // get module type
  441.     if(!ML_LoadPatterns()) return 0;        // read all patterns
  442.     if(!ML_LoadSamples()) return 0;         // read all samples
  443.     if(filename!=NULL) fclose(fp);          // close the file
  444.  
  445.     return 1;
  446. }
  447.  
  448.